package cn.wolfcode.es.service.impl;

import cn.wolfcode.entity.Destination;
import cn.wolfcode.entity.Strategy;
import cn.wolfcode.entity.Travel;
import cn.wolfcode.entity.Userinfo;
import cn.wolfcode.es.query.SearchQuery;
import cn.wolfcode.es.service.ISearchService;
import cn.wolfcode.service.IDestinationService;
import cn.wolfcode.service.IStrategyService;
import cn.wolfcode.service.ITravelService;
import cn.wolfcode.service.IUserinfoService;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class SearchServiceImpl implements ISearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private IStrategyService strategyService;
    @Autowired
    private ITravelService travelService;
    @Autowired
    private IUserinfoService userinfoService;

    @Autowired
    private IDestinationService destinationService;


    @Override
    public <T> Page<T> searchWithHighlight(String index, String type, SearchQuery qo, Class<T> clazz, String... fields) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withIndices(index)
                .withTypes(type)
                .withQuery(QueryBuilders.multiMatchQuery(qo.getKeyword(), fields));
        PageRequest pageable = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize());
        builder.withPageable(pageable);
        // 高亮前后缀
        String preTag = "<span style='color:red'>";
        String postTag = "</span>";

        HighlightBuilder.Field[] fs = new HighlightBuilder.Field[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fs[i] = new HighlightBuilder.Field(fields[i]).preTags(preTag).postTags(postTag);
        }
        builder.withHighlightFields(fs);
        return elasticsearchTemplate.queryForPage(builder.build(), clazz, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                List<T> list = new ArrayList<>();
                SearchHits hits = response.getHits();
                SearchHit[] searchHits = hits.getHits();
                for (SearchHit searchHit : searchHits) {
                    T t = mapSearchHit(searchHit, clazz);
                    list.add(t);
                }
                return new AggregatedPageImpl<>(list, pageable, hits.getTotalHits());
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                Long id = Long.parseLong(searchHit.getSourceAsMap().get("id").toString());
                T t = null;
                if (type == Userinfo.class) {
                    t = (T) userinfoService.getById(id);
                } else if (type == Strategy.class) {
                    t = (T) strategyService.getById(id);
                } else if (type == Travel.class) {
                    t = (T) travelService.getById(id);
                } else if (type == Destination.class) {
                    t = (T) destinationService.getById(id);
                }
                for (HighlightField field : searchHit.getHighlightFields().values()) {
                    try {
                        BeanUtils.setProperty(t, field.getName(), field.getFragments()[0].toString());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                return t;
            }
        });

    }
}
